package com.ssd.mixly.service.impl;


import com.ssd.mixly.service.IMqttService;
import com.ssd.mixly.service.ListenMqtt;
import org.eclipse.paho.client.mqttv3.*;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.annotation.Resource;
import java.applet.AppletContext;

/**
 * 用于处理MQTT消息的发送和接收。
 * 该类实现了 MqttCallback 接口，以便在接收到消息或连接丢失时能够执行相应的回调方法。
 */
public class MqttServiceImpl implements IMqttService, MqttCallback {


    private ListenMqtt listenMqtt;
    private ApplicationContext applicationContext;

    // MQTT代理服务器地址
    private final String broker="tcp://mixio.mixly.cn:1883";

    // 连接到MQTT代理的用户名
    private final String username="2393231117@qq.com";

    // 连接到MQTT代理的密码
    private final String password="d91f609b27e090a4e43ed3a7e47a31a2";

    //项目名
    private final String project="esp8266";

    // MQTT客户端实例
    public MqttClient client;

    private String[] topics;

    //无参构造方法
    public MqttServiceImpl() {

    }

    //构造方法
    public MqttServiceImpl(String[] topic,ApplicationContext applicationContext) {
        try {
            connect();
            this.applicationContext = applicationContext;
            listen(topic);
            topics=topic;
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 发布一条包含舵机编号和旋转时间的消息到指定主题。
     *
     * @throws MqttException 如果发布过程中发生错误
     */
    @Override
    public void send(String topic,String msg) throws MqttException {
        if (client == null || !client.isConnected()) {
            connect(); // 如果客户端未连接，则先建立连接
        }

        String sendTopic = username + "/esp8266/" + topic; // 构建发送主题
        MqttMessage mqttMessage = new MqttMessage(msg.getBytes()); // 创建MQTT消息
        client.publish(sendTopic, mqttMessage); // 发布消息
        System.out.println("已发布主题：" + topic+"已发布消息："+mqttMessage); // 打印发布的消息
    }

    /**
     * 开始监听ESP8266的状态主题。
     *
     * @throws MqttException 如果订阅过程中发生错误
     */
    @Override
    public void listen(String[] topic) throws MqttException {
        if (client == null || !client.isConnected()) {
            connect(); // 如果客户端未连接，则先建立连接
        }
        for (String t : topic) {
            String topicString = username + "/esp8266/" + t; // 构建发送主题
            client.subscribe(topicString); // 订阅ESP8266的主题
        }

    }

    /**
     * 连接到MQTT代理服务器。
     *
     * @throws MqttException 如果连接过程中发生错误
     */
    private void connect() throws MqttException {
        client = new MqttClient(broker, MqttClient.generateClientId()); // 创建MQTT客户端实例
        MqttConnectOptions options = new MqttConnectOptions();
        options.setUserName(username); // 设置用户名
        options.setPassword(password.toCharArray()); // 设置密码
        client.connect(options); // 连接到MQTT代理
        client.setCallback(this); // 设置回调接口，以便处理接收到的消息
    }

    /**
     * 当与MQTT代理的连接丢失时调用此方法。
     *
     * @param cause 导致连接丢失的原因
     */
    @Override
    public void connectionLost(Throwable cause) {
        try {
            connect();
            listen(topics);
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 当有消息到达时调用此方法。
     *
     * @param topic 消息所属的主题
     * @param message 到达的消息
     * @throws Exception 如果处理消息时发生错误
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        System.out.println("*********主题"+topic+"收到消息********: " + new String(message.getPayload())); // 打印接收到的消息


        // 从Spring上下文中获取Bean并设置给非Spring管理的对象
        if (null == listenMqtt){
            listenMqtt= applicationContext.getBean(ListenMqtt.class);
        }
        listenMqtt.listen(topic, String.valueOf(message));
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        // 消息发送完成时调用此方法
    }
}